(* Input: tar file as stream. Output: list of (file-name, file-contents) *)
let files_of_tar_stream s =
    let name = ref ""
    and length = ref 0
    and contents = ref "" 
    and block = String.make 512 (char_of_int 0) 
    and files = ref []
    and ok = ref true
    and hdr = ref true in
    let f c =
        let p = ((Stream.count s) - 1) mod 512 in
        block.[p] <- c;
        if ((p = 511) && !ok) then
            if !hdr then
            (
                hdr := false;   
                let nm = (String.sub block 0 100) in
                name := String.sub nm 0 (String.index nm (char_of_int 0));
                if((String.length !name) = 0) then
                    ok := false
                else
                    length := int_of_string ("0o" ^ (String.sub block 124 11))
            )    
            else
            (
                let diff = !length - (String.length !contents) in
                contents := !contents ^ (String.sub block 0 (min diff 512));
                if (!length = (String.length !contents)) then
                    (
                        files := List.append !files [(!name, !contents)];    
                        length := 0;
                        contents := "";
                        hdr := true;
                    )
            )   
    in        
    Stream.iter f s;
    !files

(* Compile: ocamlc tar.ml -o test
   Usage: test < some_tar_file.tar *)
let print_tarfiles (name, _) =
    Printf.printf "%s\n" name

let _ =
    let files =  (files_of_tar_stream (Stream.of_channel stdin)) in
    List.iter print_tarfiles files
